<!--
 * @Descripttion: 代码编辑器
 * @version: 1.0
 * @Author: sakuya
 * @Date: 2022年5月20日21:46:29
 * @LastEditors:
 * @LastEditTime:
-->

<template>
	<div class="sc-code-editor" :style="{'height':_height}" ref="editorContainer">
		<div class="cm-left">
			<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
				<path
					d="M3.69653 4.35645L3.29907 4.80566L3.33813 4.97559H4.36157C4.15258 6.18457 3.99633 7.27441 3.69653 8.9541C3.33813 11.0967 3.13207 11.623 3.01 11.8154C2.90258 12.0059 2.74829 12.1045 2.5393 12.1045C2.30981 12.1045 1.89477 11.9229 1.67211 11.7168C1.59204 11.6621 1.49731 11.6758 1.39672 11.7422C1.19555 11.9121 1.00024 12.1738 1.00024 12.4082C0.988519 12.7246 1.41137 13 1.81469 13C2.17016 13 2.6936 12.7773 3.24438 12.2539C3.99731 11.54 4.56079 10.5605 5.03149 8.44336C5.33422 7.0918 5.4768 6.21289 5.68969 4.97656L6.96118 4.86133L7.23657 4.35645H5.80493C6.17504 2.02832 6.46411 1.68359 6.81957 1.68359C7.0559 1.68359 7.33129 1.86523 7.6477 2.22266C7.74145 2.35156 7.88207 2.33789 7.9895 2.25C8.17016 2.14258 8.39282 1.86719 8.40747 1.61719C8.41821 1.3418 8.09008 1 7.52563 1C7.01391 1 6.22973 1.3418 5.57055 2.01367C4.99243 2.62598 4.68969 3.39062 4.48071 4.35645H3.69653ZM7.76489 5.91504C8.15942 5.38965 8.39575 5.21484 8.51782 5.21484C8.64379 5.21484 8.74438 5.33887 8.9602 6.03613L9.32934 7.22656C8.61547 8.31836 8.09301 8.92676 7.77563 8.92676C7.67016 8.92676 7.56372 8.89355 7.48852 8.81934C7.4143 8.74512 7.33227 8.68359 7.25219 8.68359C6.99047 8.68359 6.66625 9.00098 6.66039 9.39453C6.65454 9.7959 6.93579 10.083 7.30493 10.083C7.93872 10.083 8.47485 9.46094 9.51 7.81152L9.81274 8.83203C10.0725 9.70898 10.3772 10.083 10.7581 10.083C11.2288 10.083 11.8616 9.68164 12.552 8.59668L12.2629 8.2666C11.8479 8.7666 11.5725 9.00098 11.4094 9.00098C11.2278 9.00098 11.0686 8.72363 10.8586 8.04199L10.4163 6.60352C10.678 6.21777 10.9358 5.89355 11.1623 5.63477C11.4319 5.32715 11.6399 5.19629 11.7815 5.19629C11.9006 5.19629 12.0041 5.24707 12.0686 5.31836C12.1536 5.41211 12.2043 5.45605 12.3049 5.45605C12.5325 5.45605 12.884 5.16699 12.8967 4.78418C12.9084 4.42871 12.6877 4.12598 12.3049 4.12598C11.7268 4.12598 11.217 4.62402 10.2356 6.08301L10.0334 5.45703C9.75024 4.57812 9.56274 4.12598 9.16821 4.12598C8.70922 4.12598 8.07836 4.69043 7.46118 5.58496L7.76489 5.91504Z"
					fill="#7D838F"></path>
			</svg>
		</div>
		<textarea ref="textarea" v-model="contentValue"></textarea>
		<button class="custom-button" @click="handleClick">
			<svg class="svg-inline--fa fa-external-link-alt fa-w-16 _xsmall_1cwxf_139" aria-hidden="true"
				focusable="false" data-prefix="fas" data-icon="external-link-alt" role="img"
				xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
				<path class="" fill="currentColor"
					d="M432,320H400a16,16,0,0,0-16,16V448H64V128H208a16,16,0,0,0,16-16V80a16,16,0,0,0-16-16H48A48,48,0,0,0,0,112V464a48,48,0,0,0,48,48H400a48,48,0,0,0,48-48V336A16,16,0,0,0,432,320ZM488,0h-128c-21.37,0-32.05,25.91-17,41l35.73,35.73L135,320.37a24,24,0,0,0,0,34L157.67,377a24,24,0,0,0,34,0L435.28,133.32,471,169c15,15,41,4.5,41-17V24A24,24,0,0,0,488,0Z">
				</path>
			</svg>
		</button>

		<ta-quick-popup ref="taQuickPopup">
			<div style="">
				<ta-json-schema-tree :schema="jsonSchema" :expand-all="true" />
			</div>

		</ta-quick-popup>

	</div>
</template>

<script>
	import {
		markRaw
	} from "vue"

	//框架
	import CodeMirror from 'codemirror'
	import 'codemirror/lib/codemirror.css'

	//主题
	import 'codemirror/theme/idea.css'
	import 'codemirror/theme/darcula.css'

	//功能
	import 'codemirror/addon/selection/active-line'

	//语言
	import 'codemirror/mode/javascript/javascript'
	import 'codemirror/mode/sql/sql'

	//智能提示
	import 'codemirror/addon/hint/show-hint'; // 提示框插件
	// import 'codemirror/addon/hint/javascript-hint'; // JavaScript 提示逻辑
	import 'codemirror/addon/hint/show-hint.css'; // 提示框样式

	// 导入 Tern 相关插件
	import 'codemirror/addon/hint/show-hint.css';
	import 'codemirror/addon/hint/show-hint';
	import 'codemirror/addon/tern/tern.js';
	import 'codemirror/addon/tern/tern.css';

	// 导入 Tern 本身 和 定义
	import * as tern from 'tern/lib/tern';
	import ecmascriptJson from 'tern/defs/ecmascript.json';
	import browserJson from 'tern/defs/browser.json';

	import {
		renderEjsTemplate
	} from '@/utils/ejs-utils';

	// 定义叠加模式
	import 'codemirror/addon/mode/overlay';
	CodeMirror.defineMode("javascriptWithMustache", function(config) {
		// 获取原始 JavaScript 模式
		const jsMode = CodeMirror.getMode(config, "javascript");

		// 定义双大括号的匹配规则
		const mustacheOverlay = {
			token: function(stream, state) {
				// 状态管理：是否在双大括号内部
				if (state.inMustache) {
					// 尝试匹配闭合符 }}
					if (stream.eat('}')) {
						if (stream.eat('}')) {
							state.inMustache = false;
							return "mustache-delimiter"; // 闭合符
						}
						return "mustache-content"; // 单个 } 不作为闭合
					}
					// 消耗所有非 } 字符
					stream.eatWhile(/[^}]/);
					return "mustache-content"; // 双大括号内容
				}

				// 尝试匹配开始符 {{
				if (stream.match('{{', false)) {
					stream.eat('{');
					stream.eat('{');
					state.inMustache = true;
					return "mustache-delimiter"; // 开始符
				}

				// 继续其他字符的解析
				while (stream.next() != null) {
					if (stream.match('{{', false)) break;
				}
				return null;
			},
			startState: function() {
				return {
					inMustache: false
				};
			}
		};

		// 返回叠加后的模式
		return CodeMirror.overlayMode(jsMode, mustacheOverlay);
	});


	var _this;
	export default {
		name: 'ta-cm-editor',
		props: {
			modelValue: {
				type: String,
				default: ""
			},
			mode: {
				type: String,
				default: "javascriptWithMustache"
			},
			maxLines: {
				type: Number,
				default: 10,
			},
			height: {
				type: [String, Number],
				default: 'auto',
			},
			options: {
				type: Object,
				default: () => {}
			},
			theme: {
				type: String,
				default: "idea"
			},
			readOnly: {
				type: Boolean,
				default: false
			},
		},
		data() {
			return {
				jsonSchema: {
					"title": "Person",
					"type": "object",
					"description": "A person representation",
					"required": ["firstName", "lastName", "age"],
					"properties": {
						"firstName": {
							"type": "string",
							"description": "The person's first name"
						},
						"lastName": {
							"type": "string",
							"description": "The person's last name"
						},
						"age": {
							"description": "Age in years",
							"type": "integer",
							"minimum": 0,
							"maximum": 120
						},
						"email": {
							"type": "string",
							"format": "email",
							"description": "Email address"
						},
						"address": {
							"type": "object",
							"description": "Address information",
							"properties": {
								"street": {
									"type": "string"
								},
								"city": {
									"type": "string"
								},
								"state": {
									"type": "string",
									"enum": ["CA", "NY", "TX", "FL"]
								},
								"zipCode": {
									"type": "string",
									"pattern": "^[0-9]{5}(?:-[0-9]{4})?$"
								}
							},
							"required": ["street", "city"]
						},
						"phoneNumbers": {
							"type": "array",
							"description": "List of phone numbers",
							"items": {
								"type": "object",
								"properties": {
									"type": {
										"type": "string",
										"enum": ["home", "work", "mobile"],
										"default": "mobile"
									},
									"number": {
										"type": "string",
										"pattern": "^[0-9()-]+$"
									}
								},
								"required": ["number"]
							}
						}
					}
				},
				ternServer: null,
				observer: null,
				editor: null,
				contentValue: this.modelValue,
				opt: {
					theme: this.theme, //主题
					styleActiveLine: false, //高亮当前行
					lineNumbers: false, //行号
					lineWrapping: true, //自动换行
					tabSize: 4, //Tab缩进
					indentUnit: 4, //缩进单位
					indentWithTabs: false, //自动缩进
					mode: this.mode, //语言
					readOnly: this.readOnly, //只读
					// 高度
					viewportMargin: Infinity,
					extraKeys: {
						"Tab": function(cm) {
							if (cm.somethingSelected()) {
								cm.indentSelection("add"); // 缩进选中的文本
							} else {
								cm.replaceSelection("    "); // 插入Tab字符
							}
						},
						"Cmd-I": this.handleItalic,
						"Alt-I": this.handleItalic,
						"Ctrl-I": this.handleItalic
					},
					hintOptions: {
						completeSingle: false, // 是否在只有一个选项时自动补全
					},
					...this.options
				}
			}
		},
		computed: {
			_height() {
				return Number(this.height) ? Number(this.height) + 'px' : this.height
			},
		},
		watch: {
			modelValue(val) {
				this.contentValue = val
				if (val !== this.editor.getValue()) {
					this.editor.setValue(val)
					this.$nextTick(() => this.editor.refresh()) // 增加刷新
				}
			}
		},
		mounted() {
			_this = this;
			this.$nextTick(() => {
				this.initEditor()
				this.setupVisibilityObserver();
			})
		},
		beforeDestroy() {
			if (this.editor) {
				this.editor.toTextArea();
				this.editor = null;
			}
			this.ternServer = null;

			// 清理observer
			if (this.observer) {
				this.observer.disconnect();
			}
		},
		methods: {

			handleItalic(cm) {
				this.showPopup();
			},

			showPopup() {

				var cm = this.editor;

				// 获取光标位置
				const cursor = cm.getCursor();

				// 将光标位置转换为屏幕坐标
				const cursorCoords = cm.cursorCoords(cursor, 'page');

				const {
					left,
					bottom
				} = cursorCoords;

				this.$refs.taQuickPopup.showPopup({
					top: bottom,
					left: left
				});

			},

			handleClick() {

			},
			initEditor() {
				// 确保全局 tern 变量可用（CodeMirror 的 tern 插件需要）
				window.tern = tern;

				this.editor = markRaw(CodeMirror.fromTextArea(this.$refs.textarea, this.opt))

				// 自动配置高度
				this.updateEditorHeight()

				this.editor.on('change', (editor) => {
					this.contentValue = editor.getValue()
					this.$emit('update:modelValue', this.contentValue)
					/*
										console.error(renderEjsTemplate(this.contentValue, {
											$: (str) => {
												return str;
											}
										}))
					*/
				})


				// 启用 Tern 服务器
				this.setupTernServer();

				// 设置自动提示（输入字符时触发）
				let timeout;
				this.editor.on('inputRead', (cm, change) => {
					if (change.text.length === 1 && /[\w.\/]/.test(change.text[0])) {
						// 当输入字母、数字、点号或斜杠时触发提示
						clearTimeout(timeout);
						timeout = setTimeout(() => {
							this.showTernCompletions(cm)
						}, 150);
					}
				});


			},

			refresh() {
				this.editor && this.editor.refresh();
			},

			// 自动配置高度
			updateEditorHeight() {

				// 获取单行高度
				const lineHeight = this.editor.defaultTextHeight()
				const maxHeight = this.maxLines * lineHeight

				const wrapper = this.editor.getWrapperElement()
				wrapper.style.height = 'auto'
				wrapper.style.maxHeight = `${maxHeight}px`

				this.refresh()

			},
			setupTernServer() {
				// 创建 Tern 服务器
				this.ternServer = new CodeMirror.TernServer({
					defs: [ecmascriptJson, browserJson],
					plugins: {
						doc_comment: {
							fullDocs: true
						}
					},
					getFile: (name) => {
						// 获取文件内容的逻辑，简单实现
						return this.editor.getValue();
					},
					completions: true,
					typeTip: true,
					guess: true
				});

				// 将 Tern 服务器绑定到编辑器
				this.editor.ternServer = this.ternServer;
			},
			// Tern 相关方法
			showTernCompletions(cm) {
				this.ternServer.complete(cm);
			},
			setupVisibilityObserver() {
				// 创建交叉观察器
				this.observer = new IntersectionObserver((entries) => {
					entries.forEach(entry => {
						// 当元素变为可见时
						if (entry.isIntersecting) {
							// console.log('CodeMirror is now visible, refreshing...');
							this.$nextTick(() => {
								this.refresh();
							});
						}
					});
				}, {
					threshold: 0.1 // 当10%的元素可见时触发
				});

				// 开始观察编辑器容器
				this.observer.observe(this.$refs.editorContainer);
			},
			formatStrInJson(strValue) {
				return JSON.stringify(JSON.parse(strValue), null, 4)
			}
		}
	}
</script>

<style scoped>
	.sc-code-editor {
		font-size: 14px;
		border: 1px solid rgb(217, 222, 232);
		line-height: 150%;
		height: auto;
		position: relative;
		border: none;
		display: flex;
	}

	.cm-left {
		border-radius: 5px;
		border-top-right-radius: 0px;
		border-bottom-right-radius: 0px;
		border: 1px solid rgb(217, 222, 232);
		border-right: none;

		width: 30px;
		display: flex;
		align-items: center;
		justify-content: center;
		background-color: rgb(241, 243, 249);

		flex-shrink: 0;
	}

	.custom-button svg {
		width: 9px !important;
		height: 9px;
		transform: rotate(270deg);
	}

	.custom-button {
		position: absolute;
		right: 0px;
		bottom: 0px;
		z-index: 1000;
		padding: 1px 6px;
		background: white;
		color: rgb(82, 84, 86);
		border: none;
		border: 1px solid rgb(217, 222, 232);
		border-radius: 5px;
		cursor: pointer;
	}

	.sc-code-editor:deep(.CodeMirror-wrap) {
		border-radius: 5px;
		border-top-left-radius: 0px;
		border-bottom-left-radius: 0px;
		border: 1px solid rgb(217, 222, 232);
		border-left: none;
	}

	.sc-code-editor:deep(.CodeMirror) {
		width: 100%;
		flex: 1;
		height: 100%;
	}

	:deep(.cm-mustache-delimiter) {
		font-weight: bold;
		background: rgb(214, 245, 230);
		color: rgb(41, 163, 102);
	}

	:deep(.cm-mustache-content) {
		color: rgb(41, 163, 102);
		background: rgb(214, 245, 230);
	}

	:deep(.CodeMirror-sizer) {
		min-height: 25px !important;
	}
</style>


<style>
	/* 全局生效 */
	.CodeMirror-hints {
		z-index: 19900501 !important;
	}

	/*修复饿了么ui的样式异常*/
	.CodeMirror-scroll,
	.CodeMirror-sizer,
	.CodeMirror-gutter,
	.CodeMirror-gutters,
	.CodeMirror-linenumber {
		box-sizing: content-box !important;
	}
</style>
